using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Web;
using System.Xml;
using System.Xml.Serialization;

namespace Portal.Api
{
  /// <summary>
  /// Summary description for Language.
  /// </summary>
  [XmlRoot("language"), Serializable]
  public sealed class Language
  {
    private static XmlSerializer xmlLanguage = new XmlSerializer(typeof(Language));

    private Language()
    {
    }

    public static string GetText(string reference)
    {
      Language l = Load(System.Threading.Thread.CurrentThread.CurrentUICulture);
      string w = (string)l.wordsTbl[reference];
      return w == null ? reference : w;
    }

    public static string GetText(Module module, string reference)
    {
      if (module == null)
      {
        return GetText(reference);
      }
      else
      {
        Language l = Load(System.Threading.Thread.CurrentThread.CurrentUICulture, module);
        string w = (string)l.wordsTbl[reference];
        return w == null ? reference : w;
      }
    }

    private static Language Load(CultureInfo culture)
    {
      return Load(culture, null);
    }


    /// <summary>
    /// Load the language file for the current culture. If the languagefile doesn't exist, the language file of the parent culture
    /// will be loaded.
    /// </summary>
    /// <param name="culture">The Culture to start with</param>
    /// <param name="module">The module, null if no module</param>
    /// <returns></returns>
    private static Language Load(CultureInfo culture, Module module)
    {
      string origLanguage = culture.Name;
      string cacheKey = "Language_";
      if (module != null)
        cacheKey += module.Document.ModuleType + "_";
      cacheKey += culture.Name;

      // Lookup in Cache
      Language l = (Language)HttpContext.Current.Cache[cacheKey];
      if (l != null)
        return l;

      // Try to load the Languagefile, start with the specific language, and walk up recursive if not found.
      string physPath = null;
      List<string> fileDependency = new List<string>(2);
      while ((physPath == null) && !(string.IsNullOrEmpty(culture.Name)))
      {
        if (module == null)
          physPath = Config.GetLanguagePhysicalPath(culture.Name);
        else
          physPath = Config.GetModuleLanguagePhysicalPath(module.Document.ModuleType, culture.Name);

        fileDependency.Add(physPath);

        if (!File.Exists(physPath))
        {
          // The language file doesn't exist. Try the parent culture.
          physPath = null;
          culture = culture.Parent;
        }
      }

      if (physPath != null)
      {
        XmlTextReader xmlReader = new XmlTextReader(physPath);
        try
        {
          l = (Language)xmlLanguage.Deserialize(xmlReader);
          if (l == null)
            throw new PortalException("Unable to load Languagefile: " + physPath);

          UpdateLanguageProperties(l);

          // Add to Cache
          HttpContext.Current.Cache.Insert(cacheKey, l, new System.Web.Caching.CacheDependency(fileDependency.ToArray()));
        }
        catch (Exception)
        {
          throw new PortalException("Unable to load Languagefile " + physPath);
        }
        finally
        {
          xmlReader.Close();
        }
      }
      else
        throw new PortalException("Unable to load Language " + origLanguage);

      return l;
    }

    private static void UpdateLanguageProperties(Language l)
    {
      if (l.words == null)
        throw new PortalException("No words found in current Language");

      foreach (Word w in l.words)
      {
        l.wordsTbl[w.Reference] = w.Value;
      }
    }

    [XmlElement("word")]
    public Word[] words = new Word[] { };

    [XmlIgnore]
    private Hashtable wordsTbl = new Hashtable();
  }

  [Serializable]
  public class Word
  {
    public Word()
    {
      Reference = string.Empty;
      Value = string.Empty;
    }

    [XmlAttribute("ref")]
    public string Reference
    {
      get;
      set;
    }

    [XmlText]
    public string Value
    {
      get;
      set;
    }
  }
}
